package useraddress

import (
	"context"
	"encoding/json"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/resultx"
	"mall/service/user/model"
	"mall/service/user/rpc/internal/svc"
	"mall/service/user/rpc/types/user"

	"github.com/volatiletech/null/v8"
	"github.com/zeromicro/go-zero/core/logx"
)

type CreateUserAddressLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewCreateUserAddressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateUserAddressLogic {
	return &CreateUserAddressLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *CreateUserAddressLogic) CreateUserAddress(in *user.UserAddressInfo) (*user.BaseIDResp, error) {
	if in.Consignee == nil || in.Mobile == nil || in.UserId == nil || *in.UserId == 0 || len(strings.TrimSpace(*in.Consignee)) == 0 || len(strings.TrimSpace(*in.Mobile)) == 0 {
		return nil, resultx.StatusError(resultx.USER_ADDRESS_CONSIGNEE_REQUIRED, "")
	}

	if in.DetailedAddress == nil || len(strings.TrimSpace(*in.DetailedAddress)) == 0 {
		return nil, resultx.StatusError(resultx.USER_ADDRESS_ADDRESS_REQUIRED, "")
	}

	if len(in.Geographic) == 0 {
		return nil, resultx.StatusError(resultx.USER_ADDRESS_GEOGRAPHIC_REQUIRED, "")
	}

	//省  市  区  街道
	var province string
	var city string
	var district string
	var street string
	//地区代码
	var regionCodes []string
	for idx, v := range in.Geographic {
		// v.Key为nil，则为经纬度等数据，不是region地区数据
		if v.Key != nil && v.Label != nil && v.Value != nil && len(strings.TrimSpace(*v.Key)) > 0 && len(strings.TrimSpace(*v.Label)) > 0 && len(strings.TrimSpace(*v.Value)) > 0 {
			if idx == 0 {
				province = strings.TrimSpace(*v.Label)
				regionCodes = append(regionCodes, strings.TrimSpace(*v.Value))
			} else if idx == 1 {
				city = strings.TrimSpace(*v.Label)
				regionCodes = append(regionCodes, strings.TrimSpace(*v.Value))
			} else if idx == 2 {
				district = strings.TrimSpace(*v.Label)
				regionCodes = append(regionCodes, strings.TrimSpace(*v.Value))
			} else if idx == 3 {
				street = strings.TrimSpace(*v.Label)
				regionCodes = append(regionCodes, strings.TrimSpace(*v.Value))
			}
			// Todo: 支持5级数据
		}
	}

	geographic, err := json.Marshal(in.Geographic)
	if err != nil {
		return nil, resultx.StatusError(resultx.USER_ADDRESS_GEOGRAPHIC_INVALID, "")
	}

	if len(regionCodes) < 3 {
		return nil, resultx.StatusError(resultx.USER_ADDRESS_GEOGRAPHIC_INVALID, "")
	}

	var isDefault uint8
	var isDefaultIds []uint64
	if in.IsDefault != nil && *in.IsDefault > 0 {
		isDefault = 1

		filterMap := make(map[string]map[string][]any)
		filterMap[model.UserAddressColumns.UserID] = map[string][]any{
			"equalTo": {*in.UserId},
		}
		filterMap[model.UserAddressColumns.IsDefault] = map[string][]any{
			"equalTo": {true},
		}
		res, _, err := l.svcCtx.UserAddress.GetList(l.ctx, model.M{}, -1, filterMap)
		if err != nil {
			return nil, err
		}

		for _, v := range res {
			isDefaultIds = append(isDefaultIds, v.UserAddressID)
		}
	}

	tx, err := l.svcCtx.DB.BeginTx(l.ctx, nil)
	if err != nil {
		return nil, err
	}

	now := time.Now()
	address := &model.UserAddress{
		UserID:          *in.UserId,
		Consignee:       strings.TrimSpace(*in.Consignee),
		Mobile:          strings.TrimSpace(*in.Mobile),
		Province:        province,
		City:            city,
		District:        district,
		Street:          street,
		DetailedAddress: strings.TrimSpace(*in.DetailedAddress),
		RegionCode:      strings.Join(regionCodes, ","),
		Geographic:      null.JSONFrom(geographic),
		IsDefault:       isDefault,
		Status:          uint8(globalkey.StatusEnabled),
		CreatedAt:       now,
		UpdatedAt:       now,
	}
	if in.Label != nil && len(strings.TrimSpace(*in.Label)) > 0 {
		address.Label = strings.TrimSpace(*in.Label)
	}
	if in.PostalCode != nil && len(strings.TrimSpace(*in.PostalCode)) > 0 {
		address.PostalCode = strings.TrimSpace(*in.PostalCode)
	}
	err = l.svcCtx.UserAddress.Insert(l.ctx, tx, address)
	if err != nil {
		tx.Rollback()
		return nil, err
	}

	if len(isDefaultIds) > 0 {
		err = l.svcCtx.UserAddress.UpdateBatch(l.ctx, tx, isDefaultIds, model.M{
			model.UserAddressColumns.IsDefault: false,
			model.UserAddressColumns.UpdatedAt: now,
		})
		if err != nil {
			tx.Rollback()
			return nil, err
		}
	}

	tx.Commit()

	return &user.BaseIDResp{
		Id: address.UserAddressID,
	}, nil
}
